/*

#include	"unp.h"

#define FD_SETSIZE2	5
#define IDSIZE 20

char* LOG_STRING = "230 User logged in\r\n\r\n";
char* ACK_STRING = "200 OK\r\n\r\n";
char* QUIT_STRING = "221 Service closing\r\n\r\n";
char* SYNTAX_ERR_STRING = "500 Syntax error, command unrecognized\r\n\r\n";
char* LOG_ERR_STRING = "530 Not logged in\r\n\r\n";

int num_chat = 0;
int client[FD_SETSIZE2];

typedef struct buffer {
	int read_cnt;
	char *read_ptr;
	char* read_buf;
} ReadBuffer;
typedef struct user {
	int sock;
	char userid[IDSIZE];
	char *line;
	int log;
	ReadBuffer readBuffer;
} data;

ssize_t my_read(int fd, char *ptr, ReadBuffer *readBuffer);
ssize_t readcrlf_r(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer);
char* space_remover(char* dst, char* src, size_t srclen);
char* space_remover2(char* src, size_t srclen);

void removecli(int s);
void addcli(int s, struct sockaddr_in* newcliaddr);

int main(int argc, char **argv) {
	int i, j, maxi, maxfd, listenfd, connfd, sockfd;
	int nready;

	int kkk = 0;

	ssize_t n;
	fd_set rset, allset;
	char buf[MAXLINE];
	char send_buf[MAXLINE];
	char parsing[MAXLINE];
	char parsing2[MAXLINE];
	char userlist[MAXLINE];
	socklen_t clilen;
	struct sockaddr_in cliaddr, servaddr;

	char id[IDSIZE];
	char msg[MAXLINE];
	char fromid[IDSIZE];
	char toid[IDSIZE];

	char* p1;
	char* p2;

	char protocol[MAXLINE];

	int user_ok = 0;

	data userdata[FD_SETSIZE2];

	ReadBuffer* rdbuf_p;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

	Listen(listenfd, LISTENQ);

	maxfd = listenfd; // initialize
	maxi = -1; // index into client[] array

	//	for (i = 0; i < FD_SETSIZE2; i++) // FD_SETSIZE = 5
	//		client[i] = -1; // -1 indicates available entry

	for (i = 0; i < FD_SETSIZE2; i++) { // FD_SETSIZE = 5
		userdata[i].sock = -1; // -1 indicates available entry
		userdata[i].log = 0;
	}
	FD_ZERO(&allset);
	FD_SET(listenfd, &allset);
	// end fig01

	// include fig02
	for (;;) {
		printf("1111\n");

		memset(buf, 0x00, MAXLINE);
		memset(parsing, 0x00, MAXLINE);
		memset(msg, 0x00, MAXLINE);

		rset = allset; // structure assignment

		printf("waiting in put from socket\n");
		nready = Select(maxfd + 1, &rset, NULL, NULL, NULL);

		if (FD_ISSET(listenfd, &rset)) { // new client connection

			clilen = sizeof(cliaddr);
			connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef	NOTDEF
			printf("new client: %s, port %d\n",
					Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
					ntohs(cliaddr.sin_port));
#endif

			for (i = 0; i < FD_SETSIZE2; i++)
				if (userdata[i].sock < 0) {
					userdata[i].sock = connfd; // save descriptor
					break;
				}

			userdata[i].line = malloc(MAXLINE);
			rdbuf_p = &userdata[i].readBuffer;
			rdbuf_p->read_cnt = 0;
			rdbuf_p->read_buf = malloc(MAXLINE);

			if (i == FD_SETSIZE2)
				err_quit("too many clients");

			FD_SET(connfd, &allset);
			// add new descriptor to set

			if (connfd > maxfd)
				maxfd = connfd; // for select
			if (i > maxi)
				maxi = i; // max index in client[] array

			if (--nready <= 0) {
				continue; // no more readable descriptors
			}
		}

		/////////////////////////////////////////////////////

		for (i = 0; i <= maxi; i++) { // check all clients for data

			memset(buf, 0x00, MAXLINE);
			memset(send_buf, 0x00, MAXLINE);

			if ((sockfd = userdata[i].sock) < 0)
				continue;
			if (FD_ISSET(sockfd, &rset)) {

				if ((n = my_readcrlf_r(sockfd, userdata[i].line, MAXLINE,
						rdbuf_p)) == 0) {

					//4connection closed by client
					Close(sockfd);
					FD_CLR(sockfd, &allset);
					userdata[i].sock = -1;

				} else {

					printf("recv[%s]\n", userdata[i].line);
					printf("recv len[%d]\n", n);

					memset(parsing, 0x00, MAXLINE);
					memset(msg, 0x00, MAXLINE);
					memset(fromid, 0x00, IDSIZE);
					memset(toid, 0x00, IDSIZE);

					p1 = space_remover(parsing, userdata[i].line, n); // parsing is protocol

					if ((!strcmp(parsing, "USER")) && (userdata[i].log == 0)) {
						//p1 = space_remover(fromid, p1, strlen(p1)); //ID
						//printf("fromid = [%s]\n", fromid);

						p1 = space_remover2(p1, strlen(p1)); // ID
						printf("fromid = [%s]\n", p1);
						sprintf(fromid, "%s", p1);

						userdata[i].log = 1;
						for (j = 0; j <= maxi; j++) {
							if (!strcmp(userdata[j].userid, fromid))
								userdata[i].log = 0;
						}
						if (userdata[i].log == 1) {
							printf("SUCCESS LOG IN\n");
							memset(userdata[i].userid, 0x00, IDSIZE);
							sprintf(userdata[i].userid, "%s", fromid);
							userdata[i].log = 1;
							num_chat++;
							printf("connected %d people, %s is connect\n",
									num_chat, userdata[i].userid);
							//strcpy(userdata[i].userid, fromid);
							printf("%d socket save in %d \n", connfd, i);
							Writen(sockfd, LOG_STRING, strlen(LOG_STRING));

							sprintf(msg, "%s is join\n", userdata[i].userid);

							for (j = 0; j <= maxi; j++) {
								if (userdata[j].sock > 0) {
									Writen(userdata[j].sock, msg, strlen(msg));
								}
							}
						} else { // LOG error (same ID)
							Writen(userdata[i].sock, SYNTAX_ERR_STRING,
									strlen(SYNTAX_ERR_STRING));

						}

					} else if ((!strcmp(parsing, "QUIT"))
							&& (userdata[i].log == 1)) {
						printf("quit!!!\n");
						Writen(userdata[i].sock, QUIT_STRING,
								strlen(QUIT_STRING));
						num_chat--;
						userdata[i].log = 0;
						memset(userdata[i].userid, 0x00, IDSIZE);
						sprintf(msg, "%s has been left\n", userdata[i].userid);

						for (j = 0; j <= maxi; j++) {
							if (userdata[j].sock > 0) {
								Writen(userdata[j].sock, msg, strlen(msg));
							}
						}
						close(sockfd);
						free(userdata[i].line);
						free(rdbuf_p->read_buf);
						//Free(userdata[i].userid);
						FD_CLR(sockfd, &allset);
						userdata[i].sock = -1;

					} else if ((!strcmp(parsing, "WHO"))
							&& (userdata[i].log == 1)) {
						strcat(msg, "200 OK\r\n");
						for (j = 0; j <= maxi; j++) {
							if (userdata[j].sock > 0) {
								strcat(msg, userdata[j].userid);
								strcat(msg, " ");
							}
						}
						strcat(msg, "\r\n\r\n");
						Writen(sockfd, msg, strlen(msg));

					} else if ((!strcmp(parsing, "FROM"))
							&& (userdata[i].log == 1)) {
						p1 = space_remover(fromid, p1, strlen(p1)); //ID1
						printf("ID1 = [%s]\n", fromid);
						p1 = space_remover(msg, p1, strlen(p1)); //TO
						p1 = space_remover(toid, p1, strlen(p1)); //ID2
						printf("ID2 = [%s]\n", toid);

						for (j = 0; j <= maxi; j++) {
							if (!strcmp(userdata[j].userid, toid))
								user_ok = 1;
						}
						if (user_ok == 0) // User not in group
							Writen(sockfd, SYNTAX_ERR_STRING,
									strlen(SYNTAX_ERR_STRING));

						p1 = space_remover2(p1, strlen(p1)); // pa is message
						printf("message = [%s]\n", p1);
						sprintf(msg,
								"299 Message delivered\r\nFROM %s TO %s\r\n%s\r\n\r\n",
								fromid, toid, p1);
						printf("msg = [%s]\n", msg);

						if (!strcmp(toid, "all")) {
							for (j = 0; j < num_chat; j++)
								if (userdata[j].log == 1) {
									if (!strcmp(userdata[j].userid, fromid)) {
										Writen(userdata[j].sock, ACK_STRING,
												strlen(ACK_STRING));
										continue;
									}
									Writen(userdata[j].sock, msg, strlen(msg));
								}
						} else {

							for (j = 0; j < num_chat; j++)
								if (!strcmp(userdata[j].userid, toid))
									break;
							Writen(userdata[j].sock, msg, strlen(msg));
						}
					} else if (userdata[i].log == 0) {
						Writen(sockfd, LOG_ERR_STRING, strlen(LOG_ERR_STRING));

					} else { // syntax error
						Writen(sockfd, SYNTAX_ERR_STRING,
								strlen(SYNTAX_ERR_STRING));
					}
					//Writen(sockfd, userdata[i].line, strlen(userdata[i].line));

				}

				memset(userdata[i].line, 0x00, MAXLINE);

				if (--nready <= 0)
					break; // no more readable descriptors
			}
		}
	}
}

ssize_t my_read_r(int fd, char *ptr, ReadBuffer *readBuffer) {

	if (readBuffer->read_cnt <= 0) {
		memset(readBuffer->read_buf, 0x00, MAXLINE);
		again: if ((readBuffer->read_cnt = read(fd, readBuffer->read_buf,
				MAXLINE)) < 0) {
			if (errno == EINTR)
				goto again;
			return (-1);
		} else if (readBuffer->read_cnt == 0)
			return (0);
		readBuffer->read_ptr = readBuffer->read_buf;
	}

	readBuffer->read_cnt--;
	*ptr = *(readBuffer->read_ptr)++;

	return (1);
}

ssize_t readcrlf_r1(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer) {
	char *bufx = vptr;
	int rc;
	char c;
	char lastc = 0;
	int crlf = 0;
	int n = 0;

	while (maxlen > 0) {
		if ((rc = my_read_r(fd, &c, readBuffer)) != 1) {
			if (rc < 0 && errno == EINTR)
				continue;
			return rc;
		}
		if (c == '\n') {
			if (lastc == '\r') {
				*vptr = '\0';
				n = vptr - bufx;
				return n;
			}
		}
		*vptr++ = c;
		lastc = c;
		maxlen--;
	}
	return -1;
}
ssize_t my_readcrlf_r(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer) {
	ssize_t n, rc;
	char c, *ptr;
	char check[3];

	ptr = vptr;

	for (n = 1; n < maxlen; n++) {
		check[0] = check[1];
		check[1] = check[2];
		check[2] = c;
		if ((rc = my_read_r(fd, &c, readBuffer)) == 1) {
			*ptr++ = c;
			if (c == '\n' && check[2] == '\r' && check[1] == '\n'
					&& check[0] == '\r') {
				ptr--;
				*ptr-- = 0;
				*ptr-- = 0;
				*ptr-- = 0;
				n -= 4;
				break;
			}
		} else if (rc == 0) {
			*ptr = 0;
			return (n - 1);
		} else
			return (-1);
	}

	*ptr = 0;
	return (n);
}

ssize_t readcrlf_r(int fd, char *vptr, size_t maxlen, ReadBuffer *readBuffer) {
	char *bufx = vptr;
	int rc;
	char c;
	char lastc = 0;
	int crlf = 0;
	int n = 0;

	while (maxlen > 0) {
		if ((rc = my_read_r(fd, &c, readBuffer)) != 1) {
			if (rc < 0 && errno == EINTR)
				continue;
			//printf("[[[[[[[[[[[[[[[[[[[[n=%d]]]]]]]]]]]]]]\n", rc);
			return rc;
		}
		if (c == '\n') {
			if (lastc == '\r') {
				vptr--;
				*vptr = '\0';
				//printf("[[[[[[[[[[[[[[[[[[[[n=%d]]]]]]]]]]]]]]\n", vptr - bufx);
				n = vptr - bufx;

				if (readBuffer->read_ptr == '\r') {
					readBuffer->read_ptr++;
					if (readBuffer->read_ptr == '\n') {
						readBuffer->read_ptr++;
						readBuffer->read_cnt -= 2;
					} else
						readBuffer->read_ptr--;
				}

				return n;
			}
		}
		*vptr++ = c;
		lastc = c;
		maxlen--;
	}
	return -1;
}

char* space_remover(char* dst, char* src, size_t srclen) {

	size_t n;
	char c;
	char* start = src;
	char* end = src;
	int i = 0;

	for (n = 1; n <= srclen; n++) {
		if ((*src == ' ') || (*src == '\n') || (*src == '\r')) {
			src++;
			continue;
		} else {
			while ((*src != ' ') && (*src != '\n') && (*src != '\r')
					&& (*src != 0)) {
				*dst++ = *src;
				src++;
				end = src;
				n++;
			}
			*dst = 0;
			break;
		}
	}
	return end;
}

char* space_remover2(char* src, size_t srclen) {

	size_t n;
	char c;
	char* start = src;

	for (n = 1; n <= srclen; n++) {
		if ((*src == ' ') || (*src == '\n') || (*src == '\r')) {
			src++;
			continue;
		} else {
			return src;
		}
	}
	return start;
}

//void addcli(int s, struct sockaddr_in* newcliaddr) {
//	char buf[20];
//	inet_ntop(AF_INET, &newcliaddr->sin_addr, buf, sizeof(buf));
//	printf("new client : %s\n", buf);
//	client[num_chat] = s;
//	num_chat++;
//}
//
//void removecli(int s) {
//	int i;
//	for (i = 0; i < FD_SETSIZE2; i++) {
//		if (userdata[i].sock == client[s])
//			break;
//		userdata[i] = userdata[num_chat - 1];
//
//		close(client[s]);
//		if (s != num_chat - 1) {
//			client[s] = client[num_chat - 1];
//		}
//		num_chat--;
//		printf("one has been left\n");
//	}
//}



*/
